/*******************************************************************************
 * Copyright 2018 General Electric Company
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 *******************************************************************************/

package org.eclipse.keti.acs.privilege.management.dao;

import java.util.Collections;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import org.eclipse.keti.acs.model.Attribute;
import org.eclipse.keti.acs.rest.Parent;
import org.eclipse.keti.acs.zone.management.dao.ZoneEntity;

@Entity
@Table(
        name = "resource",
        uniqueConstraints = { @UniqueConstraint(columnNames = { "authorization_zone_id", "resource_identifier" }) })
public class ResourceEntity implements ZonableEntity {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "authorization_zone_id", referencedColumnName = "id", nullable = false, updatable = false)
    private ZoneEntity zone;

    @Column(name = "resource_identifier", nullable = false)
    private String resourceIdentifier;

    /**
     * Clob representing set of attributes as a JSON body.
     */
    @Column(name = "attributes", columnDefinition = "CLOB NOT NULL")
    private String attributesAsJson = "{}";

    @Transient
    private Set<Attribute> attributes = Collections.emptySet();

    @Transient
    private Set<Parent> parents = Collections.emptySet();

    /**
     * Note about all these Id's and identifiers:
     *
     * id: surrogate id generated by the rbdms, intended to FK references, etc. resourceIdentifier: The actual
     * resource URI being protected, Ex: /asset/sanramon
     */
    public ResourceEntity(final ZoneEntity zone, final String resourceIdentifier) {
        this.zone = zone;
        this.resourceIdentifier = resourceIdentifier;
    }

    public ResourceEntity() {
        // required for jackson serialization
    }

    @Override
    public Long getId() {
        return this.id;
    }

    @Override
    public void setId(final Long id) {
        this.id = id;
    }

    @Override
    public ZoneEntity getZone() {
        return this.zone;
    }

    @Override
    public void setZone(final ZoneEntity zone) {
        this.zone = zone;
    }

    public String getResourceIdentifier() {
        return this.resourceIdentifier;
    }

    public void setResourceIdentifier(final String resourceIdentifier) {
        this.resourceIdentifier = resourceIdentifier;
    }

    @Override
    public String getAttributesAsJson() {
        return this.attributesAsJson;
    }

    @Override
    public void setAttributesAsJson(final String attributesAsJson) {
        this.attributesAsJson = attributesAsJson;
    }

    @Override
    public Set<Attribute> getAttributes() {
        return this.attributes;
    }

    @Override
    public void setAttributes(final Set<Attribute> attributes) {
        if (attributes == null) {
            this.attributes = Collections.emptySet();
        } else {
            this.attributes = attributes;
        }
    }

    @Override
    public Set<Parent> getParents() {
        return this.parents;
    }

    @Override
    public void setParents(final Set<Parent> parents) {
        this.parents = parents;
    }

    @Override
    public String toString() {
        return "ResourceEntity [id=" + this.id + ", zone=" + this.zone + ", resourceIdentifier="
                + this.resourceIdentifier + ", attributesAsJson=" + this.attributesAsJson + "]";
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(this.resourceIdentifier).append(this.zone).append(this.attributesAsJson)
                .append(this.parents).toHashCode();
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj instanceof ResourceEntity) {
            ResourceEntity other = (ResourceEntity) obj;
            return new EqualsBuilder().append(this.resourceIdentifier, other.resourceIdentifier)
                    .append(this.zone, other.zone).append(this.attributesAsJson, other.attributesAsJson)
                    .append(this.parents, other.parents).isEquals();
        }
        return false;
    }

    @Override
    public String getEntityId() {
        return this.getResourceIdentifier();
    }

    @Override
    public String getEntityType() {
        return "resource";
    }
}
